<?php

namespace PhpYes\Modules\Cmd;


class CmdRun extends ParentCmdBase
{
    /** @var array */
    private $config;

    /** @var string */
    private $name;
    /** @var string */
    private $description;
    /** @var string */
    private $detailDescription;
    /** @var ArgumentDefinition[] */
    private $argumentDefinitions;

    /**
     * SubCmdBase constructor.
     * @param array $config
     * @param string|null $alias
     */
    public function __construct($config, $alias = null)
    {
        $this->config = $config;
        $this->name = 'run';
        $this->description = 'run sub command.';
        $this->detailDescription = '';
        $this->argumentDefinitions = array(
            new ArgumentDefinition('help', '-h', '--help', false, false, 'show help information and exit.'),
            new ArgumentDefinition('list', '-l', '--list', false, false, 'list sub command.'),
            new ArgumentDefinition('subCmd', '', '', false, false, 'sub command.'),
        );

        parent::__construct($alias);
    }

    /**
     * @return array
     */
    public function getConfig()
    {
        return $this->config;
    }

    /**
     * @return ArgumentDefinition[]
     */
    public function getArgumentDefinitions()
    {
        return $this->argumentDefinitions;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @return string
     */
    public function getDetailDescription()
    {
        return $this->detailDescription;
    }

    /**
     * 命令的帮助文档
     * NAME
     * SYNOPSIS
     * DESCRIPTION
     * OPTIONS
     * EXAMPLES
     * DISCUSSION
     * ...
     * @return string
     */
    public function help()
    {
        $eol = $this->getLineSeparator();

        return "NAME:{$eol}" . $this->getHangIndent() . $this->getName() . ' - ' . $this->getDescription() .

        "{$eol}{$eol}SYNOPSIS:{$eol}" . $this->getUsage() .

        "{$eol}{$eol}DESCRIPTION:{$eol}" . $this->getDetailDescription() .
        "{$eol}{$eol}OPTIONS:{$eol}" . $this->getOptionDescription() .
        "{$eol}{$eol}EXAMPLES:{$eol}" .
        "{$eol}{$eol}DISCUSSION:{$eol}";
    }

    /**
     * 执行命令
     * @param int $argc
     * @param array $argv
     * @throws \Exception
     */
    public function execute($argc, $argv)
    {
        if ($argc <= 1) {
            echo $this->help() . $this->getLineSeparator();

            return;
        }

        $secondArg = $argv[1];
        $argObj = new ArgumentObject($secondArg, $this);
        if ($argObj->getArgType() == ArgumentObject::ArgTypePosition) {
            $subCmdList = $this->config;
            $subCmdClass = isset($subCmdList[$secondArg]) ? $subCmdList[$secondArg] : null;
            if ($subCmdClass) {
                /** @var SubCmdBase $subCmd */
                $subCmd = new $subCmdClass($this, $secondArg);
                $subCmd->execute($argc - 1, array_slice($argv, 1));
            } else {
                throw new CmdException("Unknown argument {$secondArg}");
            }
        } else {
            $argDef = $argObj->getArgumentDefinition();
            $argName = $argDef->getName();
            switch ($argName) {
                case 'help':
                    echo $this->help() . $this->getLineSeparator();
                    break;
                case 'list':
                    $cmdList = new CmdList($this);
                    $cmdList->execute(null, null);
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * @return array - [alias => SubCmdClass]
     */
    public function getSubCmdList()
    {
        return $this->config;
    }
}